﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cambaz
{
  /// <summary>
  /// Türk diline özgü kök ve ek birleştirmelerini yapan mühürlü sınıf.
  /// </summary>
  public sealed class LafCambazi
  {
    /// <summary>
    /// Verilen kök desenine göre gövde türetir.
    /// </summary>
    /// <param name="kok">Ek alacak olan yalın kelime.</param>
    /// <param name="desen">Kelimeye gelecek ekin deseni. Tercihli kaynaştırma harfi "y" ile ismin -e hali için örnek desen; "{(y)}{a}"</param>
    /// <returns>Verilen desene göre türetilen kelimeyi döndürür.</returns>
    public string Turet(string kok, string desen)
    {
      return this.Turet(kok, desen, true);
    }

    /// <summary>
    /// Verilen kök desenine göre, yumuşatma tercihi ile gövde türetir.
    /// </summary>
    /// <param name="kok">Ek alacak olan yalın kelime.</param>
    /// <param name="desen">Kelimeye gelecek ekin deseni. Tercihli kaynaştırma harfi "y" ile ismin -e hali için örnek desen; "{(y)}{a}"</param>
    /// <param name="yumusat">Ek alacak olan yalın kelimeye ait son harfin, sert sessizlerin yumuşama kuralına göre davranışını belirler. Özel isimler için true kullanın.</param>
    /// <returns>Verilen desene göre türetilen kelimeyi döndürür.</returns>
    public string Turet(string kok, string desen, bool yumusat)
    {
      string ek = null;
      return this.Turet(kok, desen, yumusat, out ek);
    }

    /// <summary>
    /// Verilen kök desenine göre gövde türetir, özel kullanımlar için sona gelen eki ayrıca sunar.
    /// </summary>
    /// <param name="kok">Ek alacak olan yalın kelime.</param>
    /// <param name="desen">Kelimeye gelecek ekin deseni. Tercihli kaynaştırma harfi "y" ile ismin -e hali için örnek desen; "{(y)}{a}"</param>
    /// <param name="ek">Kelimeye gelecek ekin desene göre uygulandıktan sonraki halidir. Kaynaştırma harflerinin sözkonusu olduğu desenlerde tercih edin.</param>
    /// <returns>Verilen desene göre türetilen kelimeyi döndürür.</returns>
    public string Turet(string kok, string desen, out string ek)
    {
      return this.Turet(kok, desen, true, out ek);
    }

    /// <summary>
    /// Verilen kök desenine göre, yumuşatma tercihi ile gövde türetir, özel kullanımlar için sona gelen eki ayrıca sunar.
    /// </summary>
    /// <param name="kok">Ek alacak olan yalın kelime.</param>
    /// <param name="desen">Kelimeye gelecek ekin deseni. Tercihli kaynaştırma harfi "y" ile ismin -e hali için örnek desen; "{(y)}{a}"</param>
    /// <param name="yumusat">Ek alacak olan yalın kelimeye ait son harfin, sert sessizlerin yumuşama kuralına göre davranışını belirler. Özel isimler için true kullanın.</param>
    /// <param name="ek">Kelimeye gelecek ekin desene göre uygulandıktan sonraki halidir. Kaynaştırma harflerinin sözkonusu olduğu desenlerde tercih edin.</param>
    /// <returns>Verilen desene göre türetilen kelimeyi döndürür.</returns>
    public string Turet(string kok, string desen, bool yumusat, out string ek)
    {
      Yapi oncekiYapi = null, oncekiSesliYapi = null;

      Yapi[] mevcutYapiDizisi = Yapi.Olustur(kok, desen);

      List<Yapi> yeniYapiDizisi = new List<Yapi>();
      foreach (Yapi yapi in mevcutYapiDizisi)
      {
        if (yapi.Desen)
        {
          if (yapi.SesliHarf)
          {
            if (oncekiYapi.SesliHarf)
            {
              if (yapi.Zorunlu && yeniYapiDizisi.Count > 0)
                yeniYapiDizisi.Remove(yeniYapiDizisi[yeniYapiDizisi.Count - 1]);
              else
                continue;
            }
            else
            {
              Yapi gercekOncekiYapi = yeniYapiDizisi[yeniYapiDizisi.Count - 1];

              if (gercekOncekiYapi.KokBileseni && !gercekOncekiYapi.SesliHarf)
              {
                if (yumusat)
                {
                  if (gercekOncekiYapi.Harf == 'k')
                    gercekOncekiYapi.Harf = 'ğ';
                  else if (gercekOncekiYapi.Harf == 'p')
                    gercekOncekiYapi.Harf = 'b';
                  else if (gercekOncekiYapi.Harf == 'ç')
                    gercekOncekiYapi.Harf = 'c';
                  else if (gercekOncekiYapi.Harf == 't')
                    gercekOncekiYapi.Harf = 'd';
                }
              }
            }

            char harf = '?';
            if (oncekiSesliYapi.KalinSesliHarf)
            {
              switch (oncekiSesliYapi.Harf)
              {
                case 'a':
                  harf = Array.IndexOf(yapi.DesenKarakterleri, 'ı') > -1 ? 'ı' : 'a';
                  break;
                case 'ı':
                  harf = Array.IndexOf(yapi.DesenKarakterleri, 'ı') > -1 ? 'ı' : 'a';
                  break;
                case 'u':
                  harf = Array.IndexOf(yapi.DesenKarakterleri, 'a') > -1 ? 'a' : 'u';
                  break;
                case 'o':
                  harf = Array.IndexOf(yapi.DesenKarakterleri, 'a') > -1 ? 'a' : 'u';
                  break;
              }
            }
            else
            {
              switch (oncekiSesliYapi.Harf)
              {
                case 'e':
                  harf = Array.IndexOf(yapi.DesenKarakterleri, 'e') > -1 ? 'e' : 'i';
                  break;
                case 'i':
                  harf = Array.IndexOf(yapi.DesenKarakterleri, 'i') > -1 ? 'i' : 'e';
                  break;
                case 'ö':
                  harf = oncekiYapi.SertSessizHarf ? 'e' : 'ü';
                  break;
                case 'ü':
                  harf = Array.IndexOf(yapi.DesenKarakterleri, 'e') > -1 ? 'e' : 'ü';
                  break;
              }
            }

            yapi.Harf = harf;
            yeniYapiDizisi.Add(yapi);
          }
          else
          {
            if (yapi.Zorunlu)
            {
              if (yapi.Harf == 'k')
              {
                yapi.Harf = oncekiYapi.SertSessizHarf ? 'k' : 'ğ';
                yeniYapiDizisi.Add(yapi);
              }
              else if (yapi.Harf == 'd')
              {
                yapi.Harf = oncekiYapi.SertSessizHarf ? 't' : 'd';
                yeniYapiDizisi.Add(yapi);
              }
              else if (yapi.Harf == 'c')
              {
                yapi.Harf = oncekiYapi.SertSessizHarf ? 'ç' : 'c';
                yeniYapiDizisi.Add(yapi);
              }
            }
            else
            {
              if (oncekiYapi.SesliHarf)
                yeniYapiDizisi.Add(yapi);
            }
          }
        }
        else
        {
          if (yapi.Zorunlu)
            yeniYapiDizisi.Add(yapi);
          else
          {
            if (!yapi.SesliHarf && oncekiYapi.SesliHarf)
              yeniYapiDizisi.Add(yapi);
          }
        }

        if (yapi.SesliHarf)
          oncekiSesliYapi = yapi;
        oncekiYapi = yapi;
      }

      StringBuilder sozcukOlusturucu = new StringBuilder();
      StringBuilder ekOlusturucu = new StringBuilder();

      for (int i = 0; i < yeniYapiDizisi.Count; i++)
      {
        if (!yeniYapiDizisi[i].KokBileseni)
          ekOlusturucu.Append(yeniYapiDizisi[i].Harf);

        sozcukOlusturucu.Append(yeniYapiDizisi[i].Harf);
      }

      ek = ekOlusturucu.ToString();

      return sozcukOlusturucu.ToString();
    }
  }
}